﻿using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Supplychains.Purchase.Repositories;
using mozhi.smarterp.Finance.Treasuries.Payments.Requisition;
using mozhi.smarterp.Finance.Treasuries.Repositories;
using mozhi.smarterp.Finance.Treasuries.Services;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Finance.Treasuries.Payments
{
    public class PaymentRequisitionAppService : FinanceAppService, IPaymentRequisitionAppService
    {
        private IPaymentRequisitionRepository _repository;
        private PaymentRequisitionManager _manager;
        private IPurchaseOrderRepository _purchaseOrderRepository;


        public PaymentRequisitionAppService(PaymentRequisitionManager manager, IPaymentRequisitionRepository repository , IPurchaseOrderRepository purchaseOrderRepository)
        {
            _manager = manager;
            _repository = repository;
            _purchaseOrderRepository = purchaseOrderRepository;
        }

        public async Task<PaymentRequisitionDto> CreateAsync(PaymentRequisitionCreateDto input)
        {
            var requisition = await _manager.GetAsync(null, input.Type, input.Date, input.TradingPartnerType, input.SupplierId, input.EmployeeId, input.CustomerId,
                input.CurrencyId, input.ExchangeRate, input.IsAdvanced, input.Comment, DocumentStatusType.Creation);

            input.Items = input.Items ?? new List<PaymentRequisitionItemCreateDto>();

            var requisitionItems = new List<PaymentRequisitionItem>();

            foreach (var item in input.Items)
            {
                var requisitionItem = await _manager.GetItemAsync(null, item.SourceDocumentType, item.SourceDocumentId, item.SourceDocumentEntryId, item.PayableAmountFr, item.PayableAmount, item.RequisitionAmountFr,
                    item.DueDate, item.ExpectedPaymentDate, item.Remark);
                requisitionItems.Add(requisitionItem);
            }

            requisition.SetItems(requisitionItems);

            requisition = await _repository.InsertAsync(requisition);

            var result = ObjectMapper.Map<PaymentRequisition, PaymentRequisitionDto>(requisition);

            return result;

        }

        public async Task DeleteAsync(Guid id)
        {
            await _manager.DeleteAsync(id);
        }

        public async Task<PaymentRequisitionDto> GetAsync(Guid id)
        {
            var requisition = await _repository.GetAsync(id);

            var result = ObjectMapper.Map<PaymentRequisition, PaymentRequisitionDto>(requisition);

            await LoadOtherInfoAsync(new List<PaymentRequisitionDto> { result });

            return result;
        }

        public async Task<PagedResultDto<PaymentRequisitionDto>> GetListAsync(PaymentRequisitionPagedResultRequestDto filter)
        {
            var requisitions = await _repository.GetPagedListAsync(filter.Keyword, filter.Type, filter.IsAdvance, filter.StartDate, filter.EndDate, filter.CurrencyId, filter.SourceDocumentId , filter.SourceDocumentEntryId,
                filter.MaxResultCount, filter.SkipCount,
                filter.Sorting, true);

            var count = await _repository.GetCountAsync(filter.Keyword, filter.Type, filter.IsAdvance, filter.StartDate, filter.EndDate, filter.CurrencyId, null , filter.SourceDocumentId, filter.SourceDocumentEntryId);

            var items = ObjectMapper.Map<List<PaymentRequisition>, List<PaymentRequisitionDto>>(requisitions);

            return new PagedResultDto<PaymentRequisitionDto>()
            {
                Items = items,
                TotalCount = count
            };
        }

        public async Task<PaymentRequisitionDto> UpdateAsync(PaymentRequisitionUpdateDto input)
        {
            var requisition = await _manager.GetAsync(input.Id, input.Type, input.Date, input.TradingPartnerType, input.SupplierId, input.EmployeeId, input.CustomerId,
                input.CurrencyId, input.ExchangeRate, input.IsAdvanced, input.Comment, DocumentStatusType.Creation);

            input.Items = input.Items ?? new List<PaymentRequisitionItemUpdateDto>();

            var requisitionItems = new List<PaymentRequisitionItem>();

            foreach (var item in input.Items)
            {
                var requisitionItem = await _manager.GetItemAsync(item.Id, null, null, null, null, null, item.RequisitionAmountFr, item.DueDate, item.ExpectedPaymentDate, item.Remark);
                requisitionItems.Add(requisitionItem);
            }

            requisition.SetItems(requisitionItems);

            requisition = await _repository.UpdateAsync(requisition);

            var result = ObjectMapper.Map<PaymentRequisition, PaymentRequisitionDto>(requisition);

            return result;
        }

        public async Task<Guid> PushPaymentAsync(Guid id)
        {
            var paymentId = await _manager.PushPaymentAsync(id);

            return paymentId;

        }

        public async Task<PaymentRequisitionDto> UpdateStatusAsync(Guid id, DocumentStatusType status)
        {
            var requisition = await _repository.GetAsync(id);

            requisition.SetStatus(status);

            requisition = await _repository.UpdateAsync(requisition);

            var result = ObjectMapper.Map<PaymentRequisition, PaymentRequisitionDto>(requisition);

            return result;
        }

        #region
        private async Task LoadOtherInfoAsync(List<PaymentRequisitionDto> requisitions)
        {
            if (requisitions == null || requisitions.Count == 0)
                return;

            foreach (var requisition in requisitions)
            {
                foreach (var item in requisition.Items)
                {
                    if (!item.SourceDocumentType.HasValue)
                        continue;

                    if(item.SourceDocumentType== DocumentType.PurchaseOrder && item.SourceDocumentId.HasValue)
                    {
                        var purchaseOrder = await _purchaseOrderRepository.GetAsync(item.SourceDocumentId.Value);

                        item.SourceDocumentNumber = purchaseOrder?.Number;
                    }
                }
            }
        }
        #endregion
    }
}
